[LINUX] x86/64: Fix backward compatibility to Xen 3.0.2.
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Tue, 14 Nov 2006 17:00:05 +0000 (17:00 +0000)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Tue, 14 Nov 2006 17:00:05 +0000 (17:00 +0000)
This requires us to explicitly specify _PAGE_USER for kernel mappings.
Original patch by Jan Beulich <jbeulich@novell.com> and Gerd Hoffmann.
Signed-off-by: Keir Fraser <keir@xensource.com>
linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c
linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c
linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pgtable.h

index 640c74d67c677414514f7dccf59a14a39e5e7ea1..b2e8832b85fefa3ced087ab1ba7c2df5a4cce737 100644 (file)
@@ -249,7 +249,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
                return NULL;
        area->phys_addr = phys_addr;
        addr = (void __iomem *) area->addr;
-       flags |= _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED;
+       flags |= _KERNPG_TABLE;
        if (__direct_remap_pfn_range(&init_mm, (unsigned long)addr,
                                     phys_addr>>PAGE_SHIFT,
                                     size, __pgprot(flags), domid)) {
index 455b20b47ec6c7aed5dd1c6b64be6d75361c95f5..032c31e532af6e054a02ee569e0b1476a17a09f2 100644 (file)
 struct dma_mapping_ops* dma_ops;
 EXPORT_SYMBOL(dma_ops);
 
+#ifdef CONFIG_XEN_COMPAT_030002
+unsigned int __kernel_page_user;
+EXPORT_SYMBOL(__kernel_page_user);
+#endif
+
 extern unsigned long *contiguous_bitmap;
 
 static unsigned long dma_reserve __initdata;
@@ -527,6 +532,33 @@ void __init xen_init_pt(void)
        addr = page[pud_index(__START_KERNEL_map)];
        addr_to_page(addr, page);
 
+#ifdef CONFIG_XEN_COMPAT_030002
+       /* On Xen 3.0.2 and older we may need to explicitly specify _PAGE_USER
+          in kernel PTEs. We check that here. */
+       if (HYPERVISOR_xen_version(XENVER_version, NULL) <= 0x30000) {
+               unsigned long *pg;
+               pte_t pte;
+
+               /* Mess with the initial mapping of page 0. It's not needed. */
+               BUILD_BUG_ON(__START_KERNEL <= __START_KERNEL_map);
+               addr = page[pmd_index(__START_KERNEL_map)];
+               addr_to_page(addr, pg);
+               pte.pte = pg[pte_index(__START_KERNEL_map)];
+               BUG_ON(!(pte.pte & _PAGE_PRESENT));
+
+               /* If _PAGE_USER isn't set, we obviously do not need it. */
+               if (pte.pte & _PAGE_USER) {
+                       /* _PAGE_USER is needed, but is it set implicitly? */
+                       pte.pte &= ~_PAGE_USER;
+                       if ((HYPERVISOR_update_va_mapping(__START_KERNEL_map,
+                                                         pte, 0) != 0) ||
+                           !(pg[pte_index(__START_KERNEL_map)] & _PAGE_USER))
+                               /* We need to explicitly specify _PAGE_USER. */
+                               __kernel_page_user = _PAGE_USER;
+               }
+       }
+#endif
+
        /* Construct mapping of initial pte page in our own directories. */
        init_level4_pgt[pgd_index(__START_KERNEL_map)] = 
                mk_kernel_pgd(__pa_symbol(level3_kernel_pgt));
index ff6d94f9e0d9200c941c425e8bb563378e385b60..0c4d0a888e2ec6308a4f46245beebf990ea5485e 100644 (file)
@@ -205,8 +205,14 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long
 #define _PAGE_PROTNONE 0x080   /* If not present */
 #define _PAGE_NX        (1UL<<_PAGE_BIT_NX)
 
+#ifdef CONFIG_XEN_COMPAT_030002
+extern unsigned int __kernel_page_user;
+#else
+#define __kernel_page_user 0
+#endif
+
 #define _PAGE_TABLE    (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
-#define _KERNPG_TABLE  (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _KERNPG_TABLE  (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY | __kernel_page_user)
 
 #define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 
@@ -219,13 +225,13 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long
 #define PAGE_READONLY  __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
 #define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define __PAGE_KERNEL \
-       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
+       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX | __kernel_page_user)
 #define __PAGE_KERNEL_EXEC \
-       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | __kernel_page_user)
 #define __PAGE_KERNEL_NOCACHE \
-       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED | _PAGE_NX)
+       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED | _PAGE_NX | __kernel_page_user)
 #define __PAGE_KERNEL_RO \
-       (_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
+       (_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX | __kernel_page_user)
 #define __PAGE_KERNEL_VSYSCALL \
        (_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define __PAGE_KERNEL_VSYSCALL_NOCACHE \
@@ -422,7 +428,8 @@ static inline pud_t *pud_offset_k(pgd_t *pgd, unsigned long address)
    can temporarily clear it. */
 #define pmd_present(x) (pmd_val(x))
 #define pmd_clear(xp)  do { set_pmd(xp, __pmd(0)); } while (0)
-#define        pmd_bad(x)      ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER & ~_PAGE_PRESENT)) != (_KERNPG_TABLE & ~_PAGE_PRESENT))
+#define pmd_bad(x) ((pmd_val(x) & ~(PTE_MASK | _PAGE_USER | _PAGE_PRESENT)) \
+                   != (_KERNPG_TABLE & ~(_PAGE_USER | _PAGE_PRESENT)))
 #define pfn_pmd(nr,prot) (__pmd(((nr) << PAGE_SHIFT) | pgprot_val(prot)))
 #define pmd_pfn(x)  ((pmd_val(x) & __PHYSICAL_MASK) >> PAGE_SHIFT)